﻿using System;
using System.IO;
using System.Net;
using System.Threading;
using Fibre.Threading;

namespace ExampleProject
{
    class Program
    {
        static void Main()
        {
            SimultaneousWorker();
            UnitOfWork();
            ActionExample();
            MixedExample();
            ExceptionExample();
            ChainedExample();

            Console.WriteLine("Press any key to exit...");
            Console.Read();
        }

        private static void ChainedExample()
        {
            var webRequest = WebRequest.Create("http://www.google.com.au/search?q=example");

            var unitOfWork = new AsyncWork();

            unitOfWork
                .AddWork(webRequest.BeginGetResponse,
                            r => webRequest.EndGetResponse(r))
                .WhenComplete(c =>
                                    {
                                        var url = GetFirstResultUrl(c.Result.GetResponseStream());
                                        var firstResultRequest = WebRequest.Create(url);
                                        c.AddWork<WebResponse>(firstResultRequest.BeginGetResponse, //Begin Get
                                                firstResultRequest.EndGetResponse)    //End Get
                                                .WhenComplete(
                                                complete => ReadResponseStream(complete.Result.GetResponseStream())); //Handle complete
                                    })
                .WhenAllComplete(AllComplete)
                .PerformWork();
        }

        private static string GetFirstResultUrl(Stream getResponseStream)
        {
            getResponseStream.Dispose();
            return "http://www.microsoft.com";
        }

        private static void ExceptionExample()
        {
            new AsyncWork()
                .AddWork(() =>
                                {
                                    Thread.Sleep(1000);
                                    throw new InvalidOperationException("Oh no");
                                })
                .WhenComplete(c =>
                                    {
                                        if (c.Error != null)
                                            Console.WriteLine("Oops something went wrong: {0}", c.Error.ToString());
                                    })
                .PerformWork();
        }

        private static void MixedExample()
        {
            var webRequest = WebRequest.Create("http://www.google.com");

            new AsyncWork()
                .AddWork(() =>
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("Some synchronous work");
                    return "My Data";
                })
                .WhenComplete(c => Console.WriteLine(c.Result)) //Prints 'My Data'

                .AddWork(webRequest.BeginGetResponse, r => webRequest.EndGetResponse(r))
                .WhenComplete(c => ReadResponseStream(c.Result.GetResponseStream()))

                .WhenAllComplete(AllComplete)
                .PerformWork();
        }

        private static void ActionExample()
        {
            new AsyncWork()
                .AddWork(() =>
                                {
                                    Thread.Sleep(1000);
                                    Console.WriteLine("Some synchronous work");
                                })
                .WhenAllComplete(AllComplete)
                .PerformWork();
        }

        private static void SimultaneousWorker()
        {
            var webRequest = WebRequest.Create("http://www.google.com");
            var worker = new SimultaneousWorker();

            worker.AddWork(
                new WorkItem
                    {
                        Work = callback => webRequest.BeginGetResponse(callback, null),
                        CompletedEvents =
                            {
                                r =>
                                    {
                                        ReadResponseStream(webRequest
                                                                .EndGetResponse(r)
                                                                .GetResponseStream());
                                    }
                            }
                    });

            worker.Start(AllComplete);
        }

        private static void AllComplete()
        {
            
        }

        private static void UnitOfWork()
        {
            var webRequest = WebRequest.Create("http://www.google.com");

            var unitOfWork = new AsyncWork();

            unitOfWork
                .AddWork(webRequest.BeginGetResponse,
                            r => webRequest.EndGetResponse(r))
                .WhenComplete(c => ReadResponseStream(c.Result.GetResponseStream()))
                .WhenAllComplete(AllComplete)
                .PerformWork();
        }

        private static void UnitOfWork2()
        {
            var webRequest = WebRequest.Create("http://www.google.com");
            var webRequest2 = WebRequest.Create("http://www.microsoft.com");

            var unitOfWork = new AsyncWork();

            unitOfWork
                .AddWork<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse)
                .WhenComplete(c => ReadResponseStream(c.Result.GetResponseStream()))
                .AddWork(webRequest2.BeginGetResponse,
                         r => webRequest2.EndGetResponse(r))
                .WhenComplete(c => ReadResponseStream(c.Result.GetResponseStream()))
                .WhenAllComplete(() => Console.WriteLine("All work done!"))
                .PerformWork();

            Console.WriteLine("Press any key to exit...");
            Console.Read();
        }

        private static void ReadResponseStream(Stream obj)
        {
            obj.Dispose();
            Console.WriteLine("Work Done");
        }
    }
}
